3、Gateway API
更新于:2024年1月5
Gateway API
目录
[toc]
本节实战
实战名称 |
---|
🚩 实战:Gateway API在istio里的安装及测试-2023.12.23(测试成功) |
🚩 实战:配置请求路由-2023.12.27(测试成功) |
🚩 实战:路由到指定版本-2023.12.27(测试成功) |
🚩 实战:基于用户身份路由-2023.12.27(测试成功) |
🚩 实战:基于权重的路由-2023.12.27(测试成功) |
🚩 实战:使用 TLS 暴露服务-2023.12.27(测试成功) |
前言
Gateway API
是由 SIG-NETWORK 社区管理的开源项目,项目地址:https:istiov1.19.3(--setprofile=demo)
实验软件:
standard-install.yaml
包括所有已升级为 GA 或 Beta 的资源,包括 GatewayClass
、Gateway
、HTTPRoute
和 ReferenceGrant
,由于 Istio 已经对 Gateway API 提供了支持,所以现在我们就可以直接使用了。
experimental.yaml
包括其他的路由对象,比如 TLSRoute、TCPRoute、UDPRoute等。
- 比如现在就会自动创建一个
istio
的GatewayClass
资源对象,如下所示(另外还有一个名为istio-remote
):
[root@master1 GatewayAPI]#kubectl get gatewayclassNAMECONTROLLERACCEPTEDAGEistioistio.io/gateway-controllerTrue13mistio-remoteistio.io/unmanaged-gatewayTrue13m[root@master1 GatewayAPI]#kubectl get gatewayclass istio -oyamlapiVersion:gateway.networking.k8s.io/v1kind:GatewayClassmetadata:……spec:controllerName:istio.io/gateway-controllerdescription:ThedefaultIstioGatewayClass……[root@master1 GatewayAPI]#
因为大部分场景下在一个 Kubernetes 集群中只会有一个 Istio 集群,所以我们可以直接使用默认的 istio
这个 GatewayClass
,如果你有多个 Istio 集群,那么你可以创建多个 GatewayClass 来区分不同的集群。
2.将 httpbin 应用使用 Gateway API 暴露到外部
比如接下来我们来尝试将 httpbin 应用使用 Gateway API 暴露到外部。
部署httpbin 应用
- 首先我们需要部署一个 httpbin 应用:
kubectlapply-fsamples/httpbin/httpbin.yaml
部署一个 Gateway
资源对象
- 然后接下来同样我们需要部署一个
Gateway
资源对象,用于将流量从外部负载均衡器转发到集群内的服务,如下所示:
# default-gateway.yamlapiVersion:gateway.networking.k8s.io/v1kind:Gatewaymetadata:name:gatewaynamespace:istio-ingress# 网关资源对象所在的命名空间spec:gatewayClassName:istio# 使用默认的 istio GatewayClasslisteners:# 监听器- name:defaulthostname:"*.example.com"port:80protocol:HTTPallowedRoutes:# 允许的路由namespaces:from:All# 允许所有命名空间
Gateway
代表了逻辑负载均衡器的实例化,它是根据一个 istio 这个 GatewayClass
进行模板化的,网关在 80 端口上监听 HTTP 流量,这个特定的 GatewayClass
在部署后会自动分配一个 IP 地址,该地址会显示在 Gateway.status
中。
🔱 注意:
需要注意的是这里我们声明使用的命名空间为
istio-ingress
, 这是因为 Istio Gateway 可以直接使用 istio ingressgateway 的 Deployment,而这个 Deployment 默认是部署在istio-system
命名空间中的,我们这里单独将Gateway
资源对象创建在istio-ingress
命名空间中,那么就会自动在这个命名空间中部署一个网关控制器,用于区分默认的 istio ingressgateway。
- 所以我们需要在
istio-ingress
命名空间中创建这个Gateway
资源对象,这样才能让 istio ingressgateway 通过Gateway
资源对象来获取配置。
kubectlcreatenamespaceistio-ingress
- 然后直接应用这个资源对象即可:
$kubectlapply-fdefault-gateway.yaml##查看[root@master1 Gateway]#kubectl get po,deployment,svc,gateway -nistio-ingressNAMEREADYSTATUSRESTARTSAGEpod/gateway-istio-7474cd4d9b-mg9qg1/1Running091sNAMEREADYUP-TO-DATEAVAILABLEAGEdeployment.apps/gateway-istio1/11191sNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGEservice/gateway-istioLoadBalancer10.96.149.21<pending>15021:31861/TCP,80:31415/TCP91sNAMECLASSADDRESSPROGRAMMEDAGEgateway.gateway.networking.k8s.io/gatewayistioFalse91s[root@master1 Gateway]#
我们也可以去对比下上面生成的 gateway-istio
和 Istio 默认的 istio-ingressgateway
的 Deployment,他们的配置几乎是一样的。
🔰
完了,又报错了(已解决😘)
最终通过升级机器内核解决了。
这里排查记录就放这里把,太坑了,太菜了哦哈哈🤣
- 故障现象
Events:TypeReasonAgeFromMessage-------------------------NormalScheduled4m23sdefault-schedulerSuccessfullyassignedistio-ingress/gateway-istio-7474cd4d9b-pkmsrtonode2WarningFailedCreatePodSandBox6s(x20 over4m21s) kubelet Failed to create pod sandbox:rpc error:code =Unknown desc =failed to create containerd task:failed to create shim task:OCI runtime create failed:runc create failed:unable to start container process:error during container init:open /proc/sys/net/ipv4/ip_unprivileged_port_start:no such file or directory:unknown[root@master1 GatewayAPI]#
[root@master1 GatewayAPI]#kubectl get gateway -nistio-ingressNAMECLASSADDRESSPROGRAMMEDAGEgatewayistioFalse5m50s[root@master1 GatewayAPI]#kubectl get po -nistio-ingressNAMEREADYSTATUSRESTARTSAGEgateway-istio-7474cd4d9b-pkmsr0/1ContainerCreating05m52s[root@master1 GatewayAPI]#kubectl get svc -nistio-ingressNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGEgateway-istioLoadBalancer10.100.204.5<pending>15021:32204/TCP,80:31157/TCP5m54s[root@master1 GatewayAPI]#
- 预测原因--感觉还是和底层版本有关系。。。;
感觉像是底层pod sandbox
--pause??问题??;
可能和这个有关系:。。。。例如 containerd 或 runc 的正确版本。
- gpt
- 这个可能性很大。。。。
再次gpt
error during container init:open /proc/sys/net/ipv4/ip_unprivileged_port_start:no such file or directory:unknown
这个错误信息表明在容器初始化时发生了问题,具体是无法找到 /proc/sys/net/ipv4/ip_unprivileged_port_start
文件或目录。这个文件通常是 Linux 内核中的一部分,用于设置非特权端口的起始范围。
以下是一些建议的解决方法:
检查文件是否存在:
执行以下命令,确保
/proc/sys/net/ipv4/ip_unprivileged_port_start
文件或目录确实存在:bashls /proc/sys/net/ipv4/ip_unprivileged_port_start
如果文件不存在,可能是因为内核配置不同或者缺少相关的内核模块。这时,你可以考虑检查内核配置,确保相关功能已启用。
检查内核配置:
检查系统的内核配置,确保启用了相应的网络参数。你可以通过查看
/boot/config-$(uname -r)
文件来检查当前内核的配置:bashcat /boot/config-$(uname -r) |grep IPV4
确保类似
CONFIG_IPV4=y
或CONFIG_IP_MULTIPLE_TABLES=y
的配置项是启用的。重新加载内核模块:
如果涉及到内核模块,尝试重新加载相关的模块。例如,如果涉及到 iptables 相关的问题,你可以尝试重新加载 iptables 模块:
bashmodprobe iptable_filter
这是一个示例,具体命令可能因问题的性质而异。
更新内核:
- 如果使用的是较旧的内核版本,考虑升级到较新的稳定版本。某些问题可能在较新的内核版本中得到修复。
检查容器运行时配置:
- 如果你使用的是容器运行时(例如 runc)而不是容器引擎(例如 Docker),确保其配置正确。有时,容器运行时的配置可能导致无法找到相关的文件或目录。
检查 SELinux 或 AppArmor:
- 如果你的系统启用了 SELinux 或 AppArmor 等安全模块,确保它们的配置不会影响容器的正常运行。有时这些安全模块可能会阻止容器访问某些文件或目录。
通过上述步骤,你可以逐步排除问题并找到解决方案。如果问题仍然存在,可能需要更深入的系统调查或者查看详细的容器运行时日志以获取更多信息。
🔰 看来要升级下内核测试了……
- kubelet没有用日志
node2节点kubelet有报错
- 百度
排查方法
我删除下flannel看下把。。。
[root@master1 ~]#kubectl get po -nkube-flannel -owideNAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATESkube-flannel-ds-2ndhl1/1Running1(11d ago) 44d 172.29.9.62 node1 <none><none>kube-flannel-ds-m44dc1/1Running1(11d ago) 44d 172.29.9.61 master1 <none><none>kube-flannel-ds-s47871/1Running3(5m10s ago) 44d 172.29.9.63 node2 <none><none>[root@master1 ~]#kubectl delete po kube-flannel-ds-s4787 -n kube-flannelpod"kube-flannel-ds-s4787"deleted##已重建[root@master1 ~]#kubectl delete po kube-flannel-ds-s4787 -n kube-flannelpod"kube-flannel-ds-s4787"deleted[root@master1 ~]#kubectl get po -nkube-flannel -owideNAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATESkube-flannel-ds-2ndhl1/1Running1(11d ago) 44d 172.29.9.62 node1 <none><none>kube-flannel-ds-m44dc1/1Running1(11d ago) 44d 172.29.9.61 master1 <none><none>kube-flannel-ds-mkh5z1/1Running014s172.29.9.63node2<none><none>[root@master1 ~]#
还是不行。。。
pause版本
WarningFailedCreatePodSandBox12m(x3 over14m) kubelet Failed to create pod sandbox:rpc error:code =Unknown desc =failed to get sandbox image "registry.k8s.io/pause:3.6":failed to pull image "registry.k8s.io/pause:3.6":failed to pull and unpack image "registry.k8s.io/pause:3.6":failed to resolve reference "registry.k8s.io/pause:3.6":failed to dorequest:Head"https:sed-i's/registry.k8s.io\/pause:3.6/registry.aliyuncs.com\/google_containers\/pause:3.9/g'/etc/containerd/config.toml
- 重启node2
重启node2后,一直卡在这里。。。
- 是不是Gatway API的部署对底层例如runc等有要求呢?
如何在Gatway API官网里查看对应的依赖呢???;--没找到。。。;
这里先把runc给升级到最新版本吧。。。。;
当前node2上runc版本:
[root@node2 ~]#runc --versionruncversion1.1.5commit:v1.1.5-0-gf19387a6spec:1.0.2-devgo:go1.19.7libseccomp:2.5.1[root@node2 ~]#
但是runc是依赖于contaerind的呀,自己和老师containerd是一致的娃。。。;
结论:k8s里网络问题排查起来好难哦😭
放弃了几天
这里记录下就好,这个问题有点难搞……
[root@master1 ~]#ssh node2Lastlogin:SatDec2308:48:262023frommaster1[root@node2 ~]#ctr -n k8s.io i ls -q|greppauseregistry.aliyuncs.com/k8sxio/pause:3.8registry.aliyuncs.com/k8sxio/pause@sha256:67cc096c2abe1f29ece08439b509738a5cd11f8ff87851a06d092772d52c090e[root@node2 ~]#
- 2024.1.2 再次排查 😥
无非就是容器运行时问题?
runc?
containerd?
pause版本?
k8s版本?(不至于呀……)
记得当时我的环境和老师的是基本一致的哇……。。。;
如果这个gateway部署有问题,那么后续的
灰度测试
也是没法正常测试的呀。。。;
该怎么排查呢……啊啊啊(先)
🔰
2023.1.3 升级内核测试(完美解决)
- 当前机器内核版本(默认内核)
[root@node2 ~]#uname -r3.10.0-957.el7.x86_64
给当前机器做快照
开始升级
……
- 升级完成
[root@master1 ~]#uname -aLinuxmaster15.4.265-1.el7.elrepo.x86_64#1 SMP Wed Dec 20 13:57:20 EST 2023 x86_64 x86_64 x86_64 GNU/Linux[root@master1 ~]#ssh node1 uname -aLinuxnode15.4.265-1.el7.elrepo.x86_64#1 SMP Wed Dec 20 13:57:20 EST 2023 x86_64 x86_64 x86_64 GNU/Linux[root@master1 ~]#ssh node2 uname -aLinuxnode25.4.265-1.el7.elrepo.x86_64#1 SMP Wed Dec 20 13:57:20 EST 2023 x86_64 x86_64 x86_64 GNU/Linux[root@master1 ~]#
- 再次测试(升级完测试OK了,完美😘)
[root@master1 Gateway]#kubectl get po,deployment,svc,gateway -nistio-ingressNAMEREADYSTATUSRESTARTSAGEpod/gateway-istio-7474cd4d9b-mg9qg1/1Running091sNAMEREADYUP-TO-DATEAVAILABLEAGEdeployment.apps/gateway-istio1/11191sNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGEservice/gateway-istioLoadBalancer10.96.149.21<pending>15021:31861/TCP,80:31415/TCP91sNAMECLASSADDRESSPROGRAMMEDAGEgateway.gateway.networking.k8s.io/gatewayistioFalse91s[root@master1 Gateway]#
- 总结
一般在测试集群实验时,一定要把内核都给升级下,不然会出现很多奇怪的问题的;
使用 HTTPRoute
资源对象来定义路由规则
- 接下来我们就需要去创建一个路由规则了,也就是想要如何访问我们的 httpbin 应用,类似于 VirtualService,我们可以使用
HTTPRoute
资源对象来定义这个路由规则,如下所示:
# httpbin-route.yamlapiVersion:gateway.networking.k8s.io/v1kind:HTTPRoutemetadata:name:httpbinnamespace:defaultspec:parentRefs:# 引用定义的 Gateway 对象- name:gatewaynamespace:istio-ingresshostnames:["httpbin.example.com"] # 域名rules:# 具体的路由规则- matches:- path:type:PathPrefixvalue:/get# 匹配 /get 的请求backendRefs:# 引用的后端服务- name:httpbinport:8000
在上面的 HTTPRoute
对象中我们通过 parentRefs
字段指定要连接到的网关,只要网关允许这种连接,这将允许路由接收来自父网关的流量,在 backendRefs
中定义将要发送流量的后端。但是需要注意我们这里只定义了匹配 /get
这个路径的请求,然后将要访问的域名通过 hostnames
来定义。
- 同样直接应用该资源对象即可:
$kubectlapply-fhttpbin-route.yaml$kubectlgethttprouteNAMEHOSTNAMESAGEhttpbin["httpbin.example.com"] 5s
3.测试
- 然后我们就可以通过
httpbin.example.com
来访问 httpbin 应用了:
# $ export INGRESS_HOST=$(kubectl get gateways.gateway.networking.k8s.io gateway -n istio-ingress -ojsonpath='{.status.addresses[0].value}')exportGATEWAY_URL=$(kubectlgetpo-listio.io/gateway-name=gateway-nistio-ingress-o'jsonpath={.items[0].status.hostIP}'):$(kubectlgetsvcgateway-istio-nistio-ingress-o'jsonpath={.spec.ports[?(@.name=="default")].nodePort}')
如果你的集群可以正常使用 LoadBalancer,那么 Gateway
控制器在部署后会自动分配一个 IP 地址,该地址会显示在 Gateway.status
中。我们这里暂不支持,所以还是可以通过 NodePort 方式来进行访问。
- 然后可以使用
curl
访问 httpbin 服务:
[root@master1 Gateway]#curl -s -HHost:httpbin.example.com "http:{"args":{},"headers":{"Accept":"**","Host":"httpbin.example.com","My-Added-Header":"added-value","User-Agent":"curl/7.29.0","X-B3-Parentspanid":"05845cb74fa4dd1a","X-B3-Sampled":"1","X-B3-Spanid":"6c96baf13d681b45","X-B3-Traceid":"54df57c881116cfa05845cb74fa4dd1a","X-Envoy-Attempt-Count":"1","X-Envoy-Internal":"true","X-Forwarded-Client-Cert":"By=spiffe:}}[root@master1 Gateway]#
在上面的示例中,在配置网关之前,我们并没有去安装 Ingress 网关的 Deployment,因为在默认配置中会根据 Gateway
配置自动分发网关 Deployment
和 Service
。但是对于高级别的场景可能还是需要去手动部署。
测试结束。😘
扩展
1、自动部署
默认情况下,每个 Gateway 将自动提供相同名称的 Service 和 Deployment。如果 Gateway 发生变化(例如添加了一个新端口),这些配置将会自动更新。这些资源可以通过以下几种方式进行定义:
将
Gateway
上的注解和标签复制到 Service 和 Deployment。这就允许配置从上述字段中读取到的内容,如配置内部负载均衡器等。Istio 提供了一个额外的注解来配置生成的资源:networking.istio.io/service-type
:控制Service.spec.type
字段。例如设置 ClusterIP 为不对外暴露服务,将会默认为 LoadBalancer。
通过配置
addresses
字段可以显式设置Service.spec.loadBalancerIP
字段:
apiVersion:gateway.networking.k8s.io/v1kind:Gatewaymetadata:name:gatewayspec:addresses:- value:192.0.2.0# 仅能指定一个地址type:IPAddress
2、手动部署
如果您不希望使用自动部署,可以进行手动配置 Deployment 和 Service。完成此选项后,您将需要手动将 Gateway 链接到 Service,并保持它们的端口配置同步。
要将 Gateway 链接到 Service,需要将 addresses
字段配置为指向单个 Hostname。
apiVersion:gateway.networking.k8s.io/v1beta1kind:Gatewaymetadata:name:gatewayspec:addresses:- value:ingress.istio-gateways.svc.cluster.localtype:Hostname
当然我们这里只是一个最简单的示例,我们将在后面的课程中继续介绍 Gateway API 的更多功能。
配置请求路由
接下来我们来了解下如果通过 Gateway API 将请求动态路由到微服务的多个版本。
同样我们这里以 Bookinfo 示例为例(首先要部署 Bookinfo 应用),我们首先将所有流量路由到微服务的 v1 (版本 1),然后将应用规则根据 HTTP 请求 header 的值路由流量。
🚩 实战:配置请求路由-2023.12.27(测试成功)
- 测试环境
k8sv1.27.6(containerd:istiov1.19.3(--setprofile=demo)
实验软件: